
import 'dart:io';

import 'package:archive/archive_io.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;

import 'log_util.dart';
import 'md5_util.dart';


/// O2 目录存储工具类
/// 
/// 
/// 
/// getApplicationSupportDirectory() 内部存储目录 多端都有
/// getExternalStorageDirectory() 获取的是  android 的外部存储 （External Storage）只有Android端有
///  getApplicationDocumentsDirectory 外部存储目录 多端都有
class O2FilePathUtil {


  static const bbsPathName = 'bbs'; // bbs
  static const cmsPathName = 'cms'; // 门户
  static const portalPathName = 'portal'; // 门户
  static const processAttachmentPathName = 'process'; // 流程
  static const cloudFilePathName = 'pan'; // 云盘
  static const imFilePathName = 'im'; // 聊天
  static const logFilePathName = 'logs'; // 日志目录
  static const aiFilePathName = 'ai'; // 日志目录
  static const onnxModelPath = 'onnx'; // onnx模型目录


  /// AI 下载文件存储路径
  static Future<String?> getAIFileDownloadLocalPath(String folder, String fileName) async {
    return getFileDownloadLocalPathByType(folder, fileName, aiFilePathName);
  }

  ///
  /// bbs webview下载文件存储路径
  /// 
  static Future<String?> getBBSFileDownloadLocalPath(String folder, String fileName) async {
    return getFileDownloadLocalPathByType(folder, fileName, bbsPathName);
  }

  ///
  /// cms webview下载文件存储路径
  /// 
  static Future<String?> getCmsFileDownloadLocalPath(String folder, String fileName) async {
    return getFileDownloadLocalPathByType(folder, fileName, cmsPathName);
  }

  ///
  /// 门户webview下载文件存储路径
  /// 
  static Future<String?> getPortalFileDownloadLocalPath(String folder, String fileName) async {
    return getFileDownloadLocalPathByType(folder, fileName, portalPathName);
  }
  ///
  /// 流程文件存储路径
  /// 
  static Future<String?> getProcessFileDownloadLocalPath(String folder, String fileName) async {
    return getFileDownloadLocalPathByType(folder, fileName, processAttachmentPathName);
  }

  /// 云盘文件存储路径
  static Future<String?> getCloudDiskFileDownloadLocalPath(String folder, String fileName) async {
    return getFileDownloadLocalPathByType(folder, fileName, cloudFilePathName);
  }
  
  ///
  /// 临时目录
  /// url作为目录
  /// 
  static Future<String?> getTempFolderWithUrl(String url) async {
    try {
      String md5 = Md5Util.encode(url);
      Directory directory = await getTemporaryDirectory();
      var dir = Directory(path.join(directory.path, md5));
      if (!dir.existsSync()) {
        dir.createSync();
      }
      return dir.path;
    } catch (e) {
      // ignore: avoid_print
      print(e);
      return null;
    }
  }

  static Future<String?> getFileDownloadLocalPathByType(String folder, String fileName, String type) async {
    try {
      Directory? process = await _parentPath(type);
      if (process != null) {
        var parentDir = Directory(path.join(process.path, folder));
        if (!parentDir.existsSync()) {
          parentDir.createSync();
        }
        return path.join(parentDir.path, fileName);
      }
    } catch (e) {
      // ignore: avoid_print
      print(e);
    }
     return null;
  }

  ///
  /// 聊天文件存储路径
  /// 
  static Future<String?> getImFileDownloadLocalPath(String folder, String fileName) async {
    try {
      Directory? im = await _parentPath(imFilePathName);
      if (im != null) {
        var parentDir = Directory(path.join(im.path, folder));
        if (!parentDir.existsSync()) {
          parentDir.createSync();
        }
        return path.join(parentDir.path, fileName);
      }
    } catch (e) {
      // ignore: avoid_print
      print(e);
    }
     return null;
  }

  ///
  /// 日志目录
  /// 
  static Future<Directory?> getLogPath() async {
    return await _parentPath(logFilePathName);
  }

  ///
  /// 日志文件路径
  /// 
  static Future<String?> getLogFilePath(String fileName) async {
    try {
      Directory? log = await getLogPath();
      if (log != null) {
        return path.join(log.path, fileName);
      }
    } catch (e) {
      // ignore: avoid_print
      print(e);
    }
     return null;
  }


  ///
  /// 缓存目录文件大小统计
  /// 
  static Future<int> cacheSizeTotal() async {
    try {
      final dir = await getTemporaryDirectory();
      return await _recursionCountCacheSize(dir);
    }catch (e) {
      // ignore: avoid_print
      print(e);
      return 0;
    }
  }
  ///
  /// 清除缓存
  /// @TODO 把业务文件也删除了？
  /// 
  static Future<void> clearCache() async {
    try {
      final dir = await getTemporaryDirectory();
      await _recursionDeleteCache(dir);
    }catch (e) {
      // ignore: avoid_print
      print(e);
    }
  }

  static Future<void> _recursionDeleteCache(FileSystemEntity file) async {
      if (file is File) {
        await file.delete();
      } else if ( file is Directory) {
        final list = file.listSync();
        if (list.isNotEmpty) {
          for (var element in list) {
            await _recursionDeleteCache(element);
          }
        }
      }
  }


  static Future<int> _recursionCountCacheSize(FileSystemEntity file) async {
    if (file is File) {
      return await file.length();
    }
    if (file is Directory) {
      final list = file.listSync();
      int size = 0;
      if (list.isNotEmpty) {
        for (final element in list) {
          size += await _recursionCountCacheSize(element);
        }
      }
      return size;
    }
    return 0;
  }

 

  static Future<Directory?> _parentPath(String parentDirName) async {
    try {
      Directory directory = await getApplicationSupportDirectory();
      var dir = Directory(path.join(directory.path, parentDirName));
      if (!dir.existsSync()) {
        dir.createSync();
      }
      return dir;
    } catch (e) {
      // ignore: avoid_print
      print(e);
      return null;
    }
  }

  static Future<String> copyAssetFile2LocalPath(String src, [String? dst]) async {
      Directory? directory = await _parentPath(onnxModelPath);
      if (directory == null) {
        return '';
      }
      dst ??= path.basename(src);
      final target = path.join(directory.path, dst);
      bool exists = await   File(target).exists();
      final data = await rootBundle.load(src);
      if (!exists || File(target).lengthSync() != data.lengthInBytes) {
        final List<int> bytes =
            data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
        await File(target).writeAsBytes(bytes);
      }
      return target;
    }
    
    /// 模型目录文件路径拼接
    static Future<String> onnxModelFilePath(String fileName) async {
      Directory? directory = await _parentPath(onnxModelPath);
      if (directory == null) {
        return '';
      }
      return path.join(directory.path, fileName);
    }

    /// 解压缩 zip 文件： [zipFilePath]  
    static Future<void> unzipOnnxModel(String zipFilePath) async {
      Directory? directory = await _parentPath(onnxModelPath);
      if (directory == null) {
        return;
      }
      OLogger.d('解压 $zipFilePath 到目录 ${directory.path}');
      await extractFileToDisk(zipFilePath, directory.path);
    }

}